1/* $NetBSD: pipe.c,v 1.2 2017/02/14 01:16:46 christos Exp $ */
2
3/*++
4/* NAME
5/* pipe 8
6/* SUMMARY
7/* Postfix delivery to external command
8/* SYNOPSIS
9/* \fBpipe\fR [generic Postfix daemon options] command_attributes...
10/* DESCRIPTION
11/* The \fBpipe\fR(8) daemon processes requests from the Postfix queue
12/* manager to deliver messages to external commands.
13/* This program expects to be run from the \fBmaster\fR(8) process
14/* manager.
15/*
16/* Message attributes such as sender address, recipient address and
17/* next-hop host name can be specified as command-line macros that are
18/* expanded before the external command is executed.
19/*
20/* The \fBpipe\fR(8) daemon updates queue files and marks recipients
21/* as finished, or it informs the queue manager that delivery should
22/* be tried again at a later time. Delivery status reports are sent
23/* to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as
24/* appropriate.
25/* SINGLE-RECIPIENT DELIVERY
26/* .ad
27/* .fi
28/* Some destinations cannot handle more than one recipient per
29/* delivery request. Examples are pagers or fax machines.
30/* In addition, multi-recipient delivery is undesirable when
31/* prepending a \fBDelivered-to:\fR or \fBX-Original-To:\fR
32/* message header.
33/*
34/* To prevent Postfix from sending multiple recipients per delivery
35/* request, specify
36/* .sp
37/* .nf
38/* \fItransport\fB_destination_recipient_limit = 1\fR
39/* .fi
40/*
41/* in the Postfix \fBmain.cf\fR file, where \fItransport\fR
42/* is the name in the first column of the Postfix \fBmaster.cf\fR
43/* entry for the pipe-based delivery transport.
44/* COMMAND ATTRIBUTE SYNTAX
45/* .ad
46/* .fi
47/* The external command attributes are given in the \fBmaster.cf\fR
48/* file at the end of a service definition. The syntax is as follows:
49/* .IP "\fBchroot=\fIpathname\fR (optional)"
50/* Change the process root directory and working directory to
51/* the named directory. This happens before switching to the
52/* privileges specified with the \fBuser\fR attribute, and
53/* before executing the optional \fBdirectory=\fIpathname\fR
54/* directive. Delivery is deferred in case of failure.
55/* .sp
56/* This feature is available as of Postfix 2.3.
57/* .IP "\fBdirectory=\fIpathname\fR (optional)"
58/* Change to the named directory before executing the external command.
59/* The directory must be accessible for the user specified with the
60/* \fBuser\fR attribute (see below).
61/* The default working directory is \fB$queue_directory\fR.
62/* Delivery is deferred in case of failure.
63/* .sp
64/* This feature is available as of Postfix 2.2.
65/* .IP "\fBeol=\fIstring\fR (optional, default: \fB\en\fR)"
66/* The output record delimiter. Typically one would use either
67/* \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
68/* sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
69/* \e\fIddd\fR (up to three octal digits) and \fB\e\e\fR.
70/* .IP "\fBflags=BDFORXhqu.>\fR (optional)"
71/* Optional message processing flags. By default, a message is
72/* copied unchanged.
73/* .RS
74/* .IP \fBB\fR
75/* Append a blank line at the end of each message. This is required
76/* by some mail user agents that recognize "\fBFrom \fR" lines only
77/* when preceded by a blank line.
78/* .IP \fBD\fR
79/* Prepend a "\fBDelivered-To: \fIrecipient\fR" message header with the
80/* envelope recipient address. Note: for this to work, the
81/* \fItransport\fB_destination_recipient_limit\fR must be 1
82/* (see SINGLE-RECIPIENT DELIVERY above for details).
83/* .sp
84/* The \fBD\fR flag also enforces loop detection (Postfix 2.5 and later):
85/* if a message already contains a \fBDelivered-To:\fR header
86/* with the same recipient address, then the message is
87/* returned as undeliverable. The address comparison is case
88/* insensitive.
89/* .sp
90/* This feature is available as of Postfix 2.0.
91/* .IP \fBF\fR
92/* Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to
93/* the message content.
94/* This is expected by, for example, \fBUUCP\fR software.
95/* .IP \fBO\fR
96/* Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
97/* with the recipient address as given to Postfix. Note: for this to
98/* work, the \fItransport\fB_destination_recipient_limit\fR must be 1
99/* (see SINGLE-RECIPIENT DELIVERY above for details).
100/* .sp
101/* This feature is available as of Postfix 2.0.
102/* .IP \fBR\fR
103/* Prepend a \fBReturn-Path:\fR message header with the envelope sender
104/* address.
105/* .IP \fBX\fR
106/* Indicate that the external command performs final delivery.
107/* This flag affects the status reported in "success" DSN
108/* (delivery status notification) messages, and changes it
109/* from "relayed" into "delivered".
110/* .sp
111/* This feature is available as of Postfix 2.5.
112/* .IP \fBh\fR
113/* Fold the command-line \fB$original_recipient\fR and
114/* \fB$recipient\fR address domain part
115/* (text to the right of the right-most \fB@\fR character) to
116/* lower case; fold the entire command-line \fB$domain\fR and
117/* \fB$nexthop\fR host or domain information to lower case.
118/* This is recommended for delivery via \fBUUCP\fR.
119/* .IP \fBq\fR
120/* Quote white space and other special characters in the command-line
121/* \fB$sender\fR, \fB$original_recipient\fR and \fB$recipient\fR
122/* address localparts (text to the
123/* left of the right-most \fB@\fR character), according to an 8-bit
124/* transparent version of RFC 822.
125/* This is recommended for delivery via \fBUUCP\fR or \fBBSMTP\fR.
126/* .sp
127/* The result is compatible with the address parsing of command-line
128/* recipients by the Postfix \fBsendmail\fR(1) mail submission command.
129/* .sp
130/* The \fBq\fR flag affects only entire addresses, not the partial
131/* address information from the \fB$user\fR, \fB$extension\fR or
132/* \fB$mailbox\fR command-line macros.
133/* .IP \fBu\fR
134/* Fold the command-line \fB$original_recipient\fR and
135/* \fB$recipient\fR address localpart (text to
136/* the left of the right-most \fB@\fR character) to lower case.
137/* This is recommended for delivery via \fBUUCP\fR.
138/* .IP \fB.\fR
139/* Prepend "\fB.\fR" to lines starting with "\fB.\fR". This is needed
140/* by, for example, \fBBSMTP\fR software.
141/* .IP \fB>\fR
142/* Prepend "\fB>\fR" to lines starting with "\fBFrom \fR". This is expected
143/* by, for example, \fBUUCP\fR software.
144/* .RE
145/* .IP "\fBnull_sender\fR=\fIreplacement\fR (default: MAILER-DAEMON)"
146/* Replace the null sender address (typically used for delivery
147/* status notifications) with the specified text
148/* when expanding the \fB$sender\fR command-line macro, and
149/* when generating a From_ or Return-Path: message header.
150/*
151/* If the null sender replacement text is a non-empty string
152/* then it is affected by the \fBq\fR flag for address quoting
153/* in command-line arguments.
154/*
155/* The null sender replacement text may be empty; this form
156/* is recommended for content filters that feed mail back into
157/* Postfix. The empty sender address is not affected by the
158/* \fBq\fR flag for address quoting in command-line arguments.
159/* .sp
160/* Caution: a null sender address is easily mis-parsed by
161/* naive software. For example, when the \fBpipe\fR(8) daemon
162/* executes a command such as:
163/* .sp
164/* .nf
165/* \fIWrong\fR: command -f$sender -- $recipient
166/* .fi
167/* .IP
168/* the command will mis-parse the -f option value when the
169/* sender address is a null string. For correct parsing,
170/* specify \fB$sender\fR as an argument by itself:
171/* .sp
172/* .nf
173/* \fIRight\fR: command -f $sender -- $recipient
174/* .fi
175/* .IP
176/* This feature is available as of Postfix 2.3.
177/* .IP "\fBsize\fR=\fIsize_limit\fR (optional)"
178/* Don't deliver messages that exceed this size limit (in
179/* bytes); return them to the sender instead.
180/* .IP "\fBuser\fR=\fIusername\fR (required)"
181/* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
182/* Execute the external command with the user ID and group ID of the
183/* specified \fIusername\fR. The software refuses to execute
184/* commands with root privileges, or with the privileges of the
185/* mail system owner. If \fIgroupname\fR is specified, the
186/* corresponding group ID is used instead of the group ID of
187/* \fIusername\fR.
188/* .IP "\fBargv\fR=\fIcommand\fR... (required)"
189/* The command to be executed. This must be specified as the
190/* last command attribute.
191/* The command is executed directly, i.e. without interpretation of
192/* shell meta characters by a shell command interpreter.
193/* .sp
194/* Specify "{" and "}" around command arguments that contain
195/* whitespace (Postfix 3.0 and later). Whitespace
196/* after "{" and before "}" is ignored.
197/* .sp
198/* In the command argument vector, the following macros are recognized
199/* and replaced with corresponding information from the Postfix queue
200/* manager delivery request.
201/* .sp
202/* In addition to the form ${\fIname\fR}, the forms $\fIname\fR and
203/* the deprecated form $(\fIname\fR) are also recognized.
204/* Specify \fB$$\fR where a single \fB$\fR is wanted.
205/* .RS
206/* .IP \fB${client_address}\fR
207/* This macro expands to the remote client network address.
208/* .sp
209/* This feature is available as of Postfix 2.2.
210/* .IP \fB${client_helo}\fR
211/* This macro expands to the remote client HELO command parameter.
212/* .sp
213/* This feature is available as of Postfix 2.2.
214/* .IP \fB${client_hostname}\fR
215/* This macro expands to the remote client hostname.
216/* .sp
217/* This feature is available as of Postfix 2.2.
218/* .IP \fB${client_port}\fR
219/* This macro expands to the remote client TCP port number.
220/* .sp
221/* This feature is available as of Postfix 2.5.
222/* .IP \fB${client_protocol}\fR
223/* This macro expands to the remote client protocol.
224/* .sp
225/* This feature is available as of Postfix 2.2.
226/* .IP \fB${domain}\fR
227/* This macro expands to the domain portion of the recipient
228/* address. For example, with an address \fIuser+foo@domain\fR
229/* the domain is \fIdomain\fR.
230/* .sp
231/* This information is modified by the \fBh\fR flag for case folding.
232/* .sp
233/* This feature is available as of Postfix 2.5.
234/* .IP \fB${extension}\fR
235/* This macro expands to the extension part of a recipient address.
236/* For example, with an address \fIuser+foo@domain\fR the extension is
237/* \fIfoo\fR.
238/* .sp
239/* A command-line argument that contains \fB${extension}\fR expands
240/* into as many command-line arguments as there are recipients.
241/* .sp
242/* This information is modified by the \fBu\fR flag for case folding.
243/* .IP \fB${mailbox}\fR
244/* This macro expands to the complete local part of a recipient address.
245/* For example, with an address \fIuser+foo@domain\fR the mailbox is
246/* \fIuser+foo\fR.
247/* .sp
248/* A command-line argument that contains \fB${mailbox}\fR
249/* expands to as many command-line arguments as there are recipients.
250/* .sp
251/* This information is modified by the \fBu\fR flag for case folding.
252/* .IP \fB${nexthop}\fR
253/* This macro expands to the next-hop hostname.
254/* .sp
255/* This information is modified by the \fBh\fR flag for case folding.
256/* .IP \fB${original_recipient}\fR
257/* This macro expands to the complete recipient address before any
258/* address rewriting or aliasing.
259/* .sp
260/* A command-line argument that contains
261/* \fB${original_recipient}\fR expands to as many
262/* command-line arguments as there are recipients.
263/* .sp
264/* This information is modified by the \fBhqu\fR flags for quoting
265/* and case folding.
266/* .sp
267/* This feature is available as of Postfix 2.5.
268/* .IP \fB${queue_id}\fR
269/* This macro expands to the queue id.
270/* .sp
271/* This feature is available as of Postfix 2.11.
272/* .IP \fB${recipient}\fR
273/* This macro expands to the complete recipient address.
274/* .sp
275/* A command-line argument that contains \fB${recipient}\fR
276/* expands to as many command-line arguments as there are recipients.
277/* .sp
278/* This information is modified by the \fBhqu\fR flags for quoting
279/* and case folding.
280/* .IP \fB${sasl_method}\fR
281/* This macro expands to the name of the SASL authentication
282/* mechanism in the AUTH command when the Postfix SMTP server
283/* received the message.
284/* .sp
285/* This feature is available as of Postfix 2.2.
286/* .IP \fB${sasl_sender}\fR
287/* This macro expands to the SASL sender name (i.e. the original
288/* submitter as per RFC 4954) in the MAIL FROM command when
289/* the Postfix SMTP server received the message.
290/* .sp
291/* This feature is available as of Postfix 2.2.
292/* .IP \fB${sasl_username}\fR
293/* This macro expands to the SASL user name in the AUTH command
294/* when the Postfix SMTP server received the message.
295/* .sp
296/* This feature is available as of Postfix 2.2.
297/* .IP \fB${sender}\fR
298/* This macro expands to the envelope sender address. By default,
299/* the null sender address expands to MAILER-DAEMON; this can
300/* be changed with the \fBnull_sender\fR attribute, as described
301/* above.
302/* .sp
303/* This information is modified by the \fBq\fR flag for quoting.
304/* .IP \fB${size}\fR
305/* This macro expands to Postfix's idea of the message size, which
306/* is an approximation of the size of the message as delivered.
307/* .IP \fB${user}\fR
308/* This macro expands to the username part of a recipient address.
309/* For example, with an address \fIuser+foo@domain\fR the username
310/* part is \fIuser\fR.
311/* .sp
312/* A command-line argument that contains \fB${user}\fR expands
313/* into as many command-line arguments as there are recipients.
314/* .sp
315/* This information is modified by the \fBu\fR flag for case folding.
316/* .RE
317/* STANDARDS
318/* RFC 3463 (Enhanced status codes)
319/* DIAGNOSTICS
320/* Command exit status codes are expected to
321/* follow the conventions defined in <\fBsysexits.h\fR>.
322/* Exit status 0 means normal successful completion.
323/*
324/* In the case of a non-zero exit status, a limited amount of
325/* command output is logged, and reported in a delivery status
326/* notification. When the output begins with a 4.X.X or 5.X.X
327/* enhanced status code, the status code takes precedence over
328/* the non-zero exit status (Postfix version 2.3 and later).
329/*
330/* After successful delivery (zero exit status) a limited
331/* amount of command output is logged, and reported in "success"
332/* delivery status notifications (Postfix 3.0 and later).
333/* This command output is not examined for the presence of an
334/* enhanced status code.
335/*
336/* Problems and transactions are logged to \fBsyslogd\fR(8).
337/* Corrupted message files are marked so that the queue manager
338/* can move them to the \fBcorrupt\fR queue for further inspection.
339/* SECURITY
340/* .fi
341/* .ad
342/* This program needs a dual personality 1) to access the private
343/* Postfix queue and IPC mechanisms, and 2) to execute external
344/* commands as the specified user. It is therefore security sensitive.
345/* CONFIGURATION PARAMETERS
346/* .ad
347/* .fi
348/* Changes to \fBmain.cf\fR are picked up automatically as \fBpipe\fR(8)
349/* processes run for only a limited amount of time. Use the command
350/* "\fBpostfix reload\fR" to speed up a change.
351/*
352/* The text below provides only a parameter summary. See
353/* \fBpostconf\fR(5) for more details including examples.
354/* RESOURCE AND RATE CONTROLS
355/* .ad
356/* .fi
357/* In the text below, \fItransport\fR is the first field in a
358/* \fBmaster.cf\fR entry.
359/* .IP "\fItransport\fB_destination_concurrency_limit ($default_destination_concurrency_limit)\fR"
360/* Limit the number of parallel deliveries to the same destination,
361/* for delivery via the named \fItransport\fR.
362/* The limit is enforced by the Postfix queue manager.
363/* .IP "\fItransport\fB_destination_recipient_limit ($default_destination_recipient_limit)\fR"
364/* Limit the number of recipients per message delivery, for delivery
365/* via the named \fItransport\fR.
366/* The limit is enforced by the Postfix queue manager.
367/* .IP "\fItransport\fB_time_limit ($command_time_limit)\fR"
368/* Limit the time for delivery to external command, for delivery via
369/* the named \fItransport\fR.
370/* The limit is enforced by the pipe delivery agent.
371/*
372/* Postfix 2.4 and later support a suffix that specifies the
373/* time unit: s (seconds), m (minutes), h (hours), d (days),
374/* w (weeks). The default time unit is seconds.
375/* MISCELLANEOUS CONTROLS
376/* .ad
377/* .fi
378/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
379/* The default location of the Postfix main.cf and master.cf
380/* configuration files.
381/* .IP "\fBdaemon_timeout (18000s)\fR"
382/* How much time a Postfix daemon process may take to handle a
383/* request before it is terminated by a built-in watchdog timer.
384/* .IP "\fBdelay_logging_resolution_limit (2)\fR"
385/* The maximal number of digits after the decimal point when logging
386/* sub-second delay values.
387/* .IP "\fBexport_environment (see 'postconf -d' output)\fR"
388/* The list of environment variables that a Postfix process will export
389/* to non-Postfix processes.
390/* .IP "\fBipc_timeout (3600s)\fR"
391/* The time limit for sending or receiving information over an internal
392/* communication channel.
393/* .IP "\fBmail_owner (postfix)\fR"
394/* The UNIX system account that owns the Postfix queue and most Postfix
395/* daemon processes.
396/* .IP "\fBmax_idle (100s)\fR"
397/* The maximum amount of time that an idle Postfix daemon process waits
398/* for an incoming connection before terminating voluntarily.
399/* .IP "\fBmax_use (100)\fR"
400/* The maximal number of incoming connections that a Postfix daemon
401/* process will service before terminating voluntarily.
402/* .IP "\fBprocess_id (read-only)\fR"
403/* The process ID of a Postfix command or daemon process.
404/* .IP "\fBprocess_name (read-only)\fR"
405/* The process name of a Postfix command or daemon process.
406/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
407/* The location of the Postfix top-level queue directory.
408/* .IP "\fBrecipient_delimiter (empty)\fR"
409/* The set of characters that can separate a user name from its
410/* extension (example: user+foo), or a .forward file name from its
411/* extension (example: .forward+foo).
412/* .IP "\fBsyslog_facility (mail)\fR"
413/* The syslog facility of Postfix logging.
414/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
415/* The mail system name that is prepended to the process name in syslog
416/* records, so that "smtpd" becomes, for example, "postfix/smtpd".
417/* .PP
418/* Available in Postfix version 3.0 and later:
419/* .IP "\fBpipe_delivery_status_filter ($default_delivery_status_filter)\fR"
420/* Optional filter for the \fBpipe\fR(8) delivery agent to change the
421/* delivery status code or explanatory text of successful or unsuccessful
422/* deliveries.
423/* SEE ALSO
424/* qmgr(8), queue manager
425/* bounce(8), delivery status reports
426/* postconf(5), configuration parameters
427/* master(5), generic daemon options
428/* master(8), process manager
429/* syslogd(8), system logging
430/* LICENSE
431/* .ad
432/* .fi
433/* The Secure Mailer license must be distributed with this software.
434/* AUTHOR(S)
435/* Wietse Venema
436/* IBM T.J. Watson Research
437/* P.O. Box 704
438/* Yorktown Heights, NY 10598, USA
439/*
440/* Wietse Venema
441/* Google, Inc.
442/* 111 8th Avenue
443/* New York, NY 10011, USA
444/*--*/
445
446/* System library. */
447
448#include <sys_defs.h>
449#include <unistd.h>
450#include <stdlib.h>
451#include <string.h>
452#include <pwd.h>
453#include <grp.h>
454#include <fcntl.h>
455#include <ctype.h>
456
457#ifdef STRCASECMP_IN_STRINGS_H
458#include <strings.h>
459#endif
460
461/* Utility library. */
462
463#include <msg.h>
464#include <vstream.h>
465#include <vstring.h>
466#include <argv.h>
467#include <htable.h>
468#include <dict.h>
469#include <iostuff.h>
470#include <mymalloc.h>
471#include <mac_parse.h>
472#include <set_eugid.h>
473#include <split_at.h>
474#include <stringops.h>
475
476/* Global library. */
477
478#include <recipient_list.h>
479#include <deliver_request.h>
480#include <mail_params.h>
481#include <mail_version.h>
482#include <mail_conf.h>
483#include <bounce.h>
484#include <defer.h>
485#include <deliver_completed.h>
486#include <sent.h>
487#include <pipe_command.h>
488#include <mail_copy.h>
489#include <mail_addr.h>
490#include <canon_addr.h>
491#include <split_addr.h>
492#include <off_cvt.h>
493#include <quote_822_local.h>
494#include <flush_clnt.h>
495#include <dsn_util.h>
496#include <dsn_buf.h>
497#include <sys_exits.h>
498#include <delivered_hdr.h>
499#include <fold_addr.h>
500#include <mail_parm_split.h>
501
502/* Single server skeleton. */
503
504#include <mail_server.h>
505
506/* Application-specific. */
507
508 /*
509 * The mini symbol table name and keys used for expanding macros in
510 * command-line arguments.
511 *
512 * XXX Update the parse_callback() routine when something gets added here,
513 * even when the macro is not recipient dependent.
514 */
515#define PIPE_DICT_TABLE "pipe_command" /* table name */
516#define PIPE_DICT_NEXTHOP "nexthop" /* key */
517#define PIPE_DICT_RCPT "recipient" /* key */
518#define PIPE_DICT_ORIG_RCPT "original_recipient" /* key */
519#define PIPE_DICT_SENDER "sender"/* key */
520#define PIPE_DICT_USER "user" /* key */
521#define PIPE_DICT_EXTENSION "extension" /* key */
522#define PIPE_DICT_MAILBOX "mailbox" /* key */
523#define PIPE_DICT_DOMAIN "domain"/* key */
524#define PIPE_DICT_SIZE "size" /* key */
525#define PIPE_DICT_CLIENT_ADDR "client_address" /* key */
526#define PIPE_DICT_CLIENT_NAME "client_hostname" /* key */
527#define PIPE_DICT_CLIENT_PORT "client_port" /* key */
528#define PIPE_DICT_CLIENT_PROTO "client_protocol" /* key */
529#define PIPE_DICT_CLIENT_HELO "client_helo" /* key */
530#define PIPE_DICT_SASL_METHOD "sasl_method" /* key */
531#define PIPE_DICT_SASL_USERNAME "sasl_username" /* key */
532#define PIPE_DICT_SASL_SENDER "sasl_sender" /* key */
533#define PIPE_DICT_QUEUE_ID "queue_id" /* key */
534
535 /*
536 * Flags used to pass back the type of special parameter found by
537 * parse_callback.
538 */
539#define PIPE_FLAG_RCPT (1<<0)
540#define PIPE_FLAG_USER (1<<1)
541#define PIPE_FLAG_EXTENSION (1<<2)
542#define PIPE_FLAG_MAILBOX (1<<3)
543#define PIPE_FLAG_DOMAIN (1<<4)
544#define PIPE_FLAG_ORIG_RCPT (1<<5)
545
546 /*
547 * Additional flags. These are colocated with mail_copy() flags. Allow some
548 * space for extension of the mail_copy() interface.
549 */
550#define PIPE_OPT_FOLD_BASE (16)
551#define PIPE_OPT_FOLD_USER (FOLD_ADDR_USER << PIPE_OPT_FOLD_BASE)
552#define PIPE_OPT_FOLD_HOST (FOLD_ADDR_HOST << PIPE_OPT_FOLD_BASE)
553#define PIPE_OPT_QUOTE_LOCAL (1 << (PIPE_OPT_FOLD_BASE + 2))
554#define PIPE_OPT_FINAL_DELIVERY (1 << (PIPE_OPT_FOLD_BASE + 3))
555
556#define PIPE_OPT_FOLD_ALL (FOLD_ADDR_ALL << PIPE_OPT_FOLD_BASE)
557#define PIPE_OPT_FOLD_FLAGS(f) \
558 (((f) & PIPE_OPT_FOLD_ALL) >> PIPE_OPT_FOLD_BASE)
559
560 /*
561 * Tunable parameters. Values are taken from the config file, after
562 * prepending the service name to _name, and so on.
563 */
564int var_command_maxtime; /* You can now leave this here. */
565
566 /*
567 * Other main.cf parameters.
568 */
569char *var_pipe_dsn_filter;
570
571 /*
572 * For convenience. Instead of passing around lists of parameters, bundle
573 * them up in convenient structures.
574 */
575
576 /*
577 * Structure for service-specific configuration parameters.
578 */
579typedef struct {
580 int time_limit; /* per-service time limit */
581} PIPE_PARAMS;
582
583 /*
584 * Structure for command-line parameters.
585 */
586typedef struct {
587 char **command; /* argument vector */
588 uid_t uid; /* command privileges */
589 gid_t gid; /* command privileges */
590 int flags; /* mail_copy() flags */
591 char *exec_dir; /* working directory */
592 char *chroot_dir; /* chroot directory */
593 VSTRING *eol; /* output record delimiter */
594 VSTRING *null_sender; /* null sender expansion */
595 off_t size_limit; /* max size in bytes we will accept */
596} PIPE_ATTR;
597
598 /*
599 * Structure for command-line parameter macro expansion.
600 */
601typedef struct {
602 const char *service; /* for warnings */
603 int expand_flag; /* callback result */
604} PIPE_STATE;
605
606 /*
607 * Silly little macros.
608 */
609#define STR vstring_str
610
611/* parse_callback - callback for mac_parse() */
612
613static int parse_callback(int type, VSTRING *buf, void *context)
614{
615 PIPE_STATE *state = (PIPE_STATE *) context;
616 struct cmd_flags {
617 const char *name;
618 int flags;
619 };
620 static struct cmd_flags cmd_flags[] = {
621 PIPE_DICT_NEXTHOP, 0,
622 PIPE_DICT_RCPT, PIPE_FLAG_RCPT,
623 PIPE_DICT_ORIG_RCPT, PIPE_FLAG_ORIG_RCPT,
624 PIPE_DICT_SENDER, 0,
625 PIPE_DICT_USER, PIPE_FLAG_USER,
626 PIPE_DICT_EXTENSION, PIPE_FLAG_EXTENSION,
627 PIPE_DICT_MAILBOX, PIPE_FLAG_MAILBOX,
628 PIPE_DICT_DOMAIN, PIPE_FLAG_DOMAIN,
629 PIPE_DICT_SIZE, 0,
630 PIPE_DICT_CLIENT_ADDR, 0,
631 PIPE_DICT_CLIENT_NAME, 0,
632 PIPE_DICT_CLIENT_PORT, 0,
633 PIPE_DICT_CLIENT_PROTO, 0,
634 PIPE_DICT_CLIENT_HELO, 0,
635 PIPE_DICT_SASL_METHOD, 0,
636 PIPE_DICT_SASL_USERNAME, 0,
637 PIPE_DICT_SASL_SENDER, 0,
638 PIPE_DICT_QUEUE_ID, 0,
639 0, 0,
640 };
641 struct cmd_flags *p;
642
643 /*
644 * See if this command-line argument references a special macro.
645 */
646 if (type == MAC_PARSE_VARNAME) {
647 for (p = cmd_flags; /* see below */ ; p++) {
648 if (p->name == 0) {
649 msg_warn("file %s/%s: service %s: unknown macro name: \"%s\"",
650 var_config_dir, MASTER_CONF_FILE,
651 state->service, vstring_str(buf));
652 return (MAC_PARSE_ERROR);
653 } else if (strcmp(vstring_str(buf), p->name) == 0) {
654 state->expand_flag |= p->flags;
655 return (0);
656 }
657 }
658 }
659 return (0);
660}
661
662/* morph_recipient - morph a recipient address */
663
664static void morph_recipient(VSTRING *buf, const char *address, int flags)
665{
666 VSTRING *temp = vstring_alloc(100);
667
668 /*
669 * Quote the recipient address as appropriate.
670 */
671 if (flags & PIPE_OPT_QUOTE_LOCAL)
672 quote_822_local(temp, address);
673 else
674 vstring_strcpy(temp, address);
675
676 /*
677 * Fold the recipient address as appropriate.
678 */
679 fold_addr(buf, STR(temp), PIPE_OPT_FOLD_FLAGS(flags));
680
681 vstring_free(temp);
682}
683
684/* expand_argv - expand macros in the argument vector */
685
686static ARGV *expand_argv(const char *service, char **argv,
687 RECIPIENT_LIST *rcpt_list, int flags)
688{
689 VSTRING *buf = vstring_alloc(100);
690 ARGV *result;
691 char **cpp;
692 PIPE_STATE state;
693 int i;
694 char *ext;
695 char *dom;
696
697 /*
698 * This appears to be simple operation (replace $name by its expansion).
699 * However, it becomes complex because a command-line argument that
700 * references $recipient must expand to as many command-line arguments as
701 * there are recipients (that's wat programs called by sendmail expect).
702 * So we parse each command-line argument, and depending on what we find,
703 * we either expand the argument just once, or we expand it once for each
704 * recipient. In either case we end up parsing the command-line argument
705 * twice. The amount of CPU time wasted will be negligible.
706 *
707 * Note: we can't use recursive macro expansion here, because recursion
708 * would screw up mail addresses that contain $ characters.
709 */
710#define NO 0
711#define EARLY_RETURN(x) { argv_free(result); vstring_free(buf); return (x); }
712
713 result = argv_alloc(1);
714 for (cpp = argv; *cpp; cpp++) {
715 state.service = service;
716 state.expand_flag = 0;
717 if (mac_parse(*cpp, parse_callback, (void *) &state) & MAC_PARSE_ERROR)
718 EARLY_RETURN(0);
719 if (state.expand_flag == 0) { /* no $recipient etc. */
720 argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
721 } else { /* contains $recipient etc. */
722 for (i = 0; i < rcpt_list->len; i++) {
723
724 /*
725 * This argument contains $recipient.
726 */
727 if (state.expand_flag & PIPE_FLAG_RCPT) {
728 morph_recipient(buf, rcpt_list->info[i].address, flags);
729 dict_update(PIPE_DICT_TABLE, PIPE_DICT_RCPT, STR(buf));
730 }
731
732 /*
733 * This argument contains $original_recipient.
734 */
735 if (state.expand_flag & PIPE_FLAG_ORIG_RCPT) {
736 morph_recipient(buf, rcpt_list->info[i].orig_addr, flags);
737 dict_update(PIPE_DICT_TABLE, PIPE_DICT_ORIG_RCPT, STR(buf));
738 }
739
740 /*
741 * This argument contains $user. Extract the plain user name.
742 * Either anything to the left of the extension delimiter or,
743 * in absence of the latter, anything to the left of the
744 * rightmost @.
745 *
746 * Beware: if the user name is blank (e.g. +user@host), the
747 * argument is suppressed. This is necessary to allow for
748 * cyrus bulletin-board (global mailbox) delivery. XXX But,
749 * skipping empty user parts will also prevent other
750 * expansions of this specific command-line argument.
751 */
752 if (state.expand_flag & PIPE_FLAG_USER) {
753 morph_recipient(buf, rcpt_list->info[i].address,
754 flags & PIPE_OPT_FOLD_ALL);
755 if (split_at_right(STR(buf), '@') == 0)
756 msg_warn("no @ in recipient address: %s",
757 rcpt_list->info[i].address);
758 if (*var_rcpt_delim)
759 split_addr(STR(buf), var_rcpt_delim);
760 if (*STR(buf) == 0)
761 continue;
762 dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
763 }
764
765 /*
766 * This argument contains $extension. Extract the recipient
767 * extension: anything between the leftmost extension
768 * delimiter and the rightmost @. The extension may be blank.
769 */
770 if (state.expand_flag & PIPE_FLAG_EXTENSION) {
771 morph_recipient(buf, rcpt_list->info[i].address,
772 flags & PIPE_OPT_FOLD_ALL);
773 if (split_at_right(STR(buf), '@') == 0)
774 msg_warn("no @ in recipient address: %s",
775 rcpt_list->info[i].address);
776 if (*var_rcpt_delim == 0
777 || (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
778 ext = ""; /* insert null arg */
779 dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
780 }
781
782 /*
783 * This argument contains $mailbox. Extract the mailbox name:
784 * anything to the left of the rightmost @.
785 */
786 if (state.expand_flag & PIPE_FLAG_MAILBOX) {
787 morph_recipient(buf, rcpt_list->info[i].address,
788 flags & PIPE_OPT_FOLD_ALL);
789 if (split_at_right(STR(buf), '@') == 0)
790 msg_warn("no @ in recipient address: %s",
791 rcpt_list->info[i].address);
792 dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
793 }
794
795 /*
796 * This argument contains $domain. Extract the domain name:
797 * anything to the right of the rightmost @.
798 */
799 if (state.expand_flag & PIPE_FLAG_DOMAIN) {
800 morph_recipient(buf, rcpt_list->info[i].address,
801 flags & PIPE_OPT_FOLD_ALL);
802 dom = split_at_right(STR(buf), '@');
803 if (dom == 0) {
804 msg_warn("no @ in recipient address: %s",
805 rcpt_list->info[i].address);
806 dom = ""; /* insert null arg */
807 }
808 dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom);
809 }
810
811 /*
812 * Done.
813 */
814 argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
815 }
816 }
817 }
818 argv_terminate(result);
819 vstring_free(buf);
820 return (result);
821}
822
823/* get_service_params - get service-name dependent config information */
824
825static void get_service_params(PIPE_PARAMS *config, char *service)
826{
827 const char *myname = "get_service_params";
828
829 /*
830 * Figure out the command time limit for this transport.
831 */
832 config->time_limit =
833 get_mail_conf_time2(service, _MAXTIME, var_command_maxtime, 's', 1, 0);
834
835 /*
836 * Give the poor tester a clue of what is going on.
837 */
838 if (msg_verbose)
839 msg_info("%s: time_limit %d", myname, config->time_limit);
840}
841
842/* get_service_attr - get command-line attributes */
843
844static void get_service_attr(PIPE_ATTR *attr, char **argv)
845{
846 const char *myname = "get_service_attr";
847 struct passwd *pwd;
848 struct group *grp;
849 char *user; /* user name */
850 char *group; /* group name */
851 char *size; /* max message size */
852 char *cp;
853
854 /*
855 * Initialize.
856 */
857 user = 0;
858 group = 0;
859 attr->command = 0;
860 attr->flags = 0;
861 attr->exec_dir = 0;
862 attr->chroot_dir = 0;
863 attr->eol = vstring_strcpy(vstring_alloc(1), "\n");
864 attr->null_sender = vstring_strcpy(vstring_alloc(1), MAIL_ADDR_MAIL_DAEMON);
865 attr->size_limit = 0;
866
867 /*
868 * Iterate over the command-line attribute list.
869 */
870 for ( /* void */ ; *argv != 0; argv++) {
871
872 /*
873 * flags=stuff
874 */
875 if (strncasecmp("flags=", *argv, sizeof("flags=") - 1) == 0) {
876 for (cp = *argv + sizeof("flags=") - 1; *cp; cp++) {
877 switch (*cp) {
878 case 'B':
879 attr->flags |= MAIL_COPY_BLANK;
880 break;
881 case 'D':
882 attr->flags |= MAIL_COPY_DELIVERED;
883 break;
884 case 'F':
885 attr->flags |= MAIL_COPY_FROM;
886 break;
887 case 'O':
888 attr->flags |= MAIL_COPY_ORIG_RCPT;
889 break;
890 case 'R':
891 attr->flags |= MAIL_COPY_RETURN_PATH;
892 break;
893 case 'X':
894 attr->flags |= PIPE_OPT_FINAL_DELIVERY;
895 break;
896 case '.':
897 attr->flags |= MAIL_COPY_DOT;
898 break;
899 case '>':
900 attr->flags |= MAIL_COPY_QUOTE;
901 break;
902 case 'h':
903 attr->flags |= PIPE_OPT_FOLD_HOST;
904 break;
905 case 'q':
906 attr->flags |= PIPE_OPT_QUOTE_LOCAL;
907 break;
908 case 'u':
909 attr->flags |= PIPE_OPT_FOLD_USER;
910 break;
911 default:
912 msg_fatal("unknown flag: %c (ignored)", *cp);
913 break;
914 }
915 }
916 }
917
918 /*
919 * user=username[:groupname]
920 */
921 else if (strncasecmp("user=", *argv, sizeof("user=") - 1) == 0) {
922 user = *argv + sizeof("user=") - 1;
923 if ((group = split_at(user, ':')) != 0) /* XXX clobbers argv */
924 if (*group == 0)
925 group = 0;
926 if ((pwd = getpwnam(user)) == 0)
927 msg_fatal("%s: unknown username: %s", myname, user);
928 attr->uid = pwd->pw_uid;
929 if (group != 0) {
930 if ((grp = getgrnam(group)) == 0)
931 msg_fatal("%s: unknown group: %s", myname, group);
932 attr->gid = grp->gr_gid;
933 } else {
934 attr->gid = pwd->pw_gid;
935 }
936 }
937
938 /*
939 * directory=string
940 */
941 else if (strncasecmp("directory=", *argv, sizeof("directory=") - 1) == 0) {
942 attr->exec_dir = mystrdup(*argv + sizeof("directory=") - 1);
943 }
944
945 /*
946 * chroot=string
947 */
948 else if (strncasecmp("chroot=", *argv, sizeof("chroot=") - 1) == 0) {
949 attr->chroot_dir = mystrdup(*argv + sizeof("chroot=") - 1);
950 }
951
952 /*
953 * eol=string
954 */
955 else if (strncasecmp("eol=", *argv, sizeof("eol=") - 1) == 0) {
956 unescape(attr->eol, *argv + sizeof("eol=") - 1);
957 }
958
959 /*
960 * null_sender=string
961 */
962 else if (strncasecmp("null_sender=", *argv, sizeof("null_sender=") - 1) == 0) {
963 vstring_strcpy(attr->null_sender, *argv + sizeof("null_sender=") - 1);
964 }
965
966 /*
967 * size=max_message_size (in bytes)
968 */
969 else if (strncasecmp("size=", *argv, sizeof("size=") - 1) == 0) {
970 size = *argv + sizeof("size=") - 1;
971 if ((attr->size_limit = off_cvt_string(size)) < 0)
972 msg_fatal("%s: bad size= value: %s", myname, size);
973 }
974
975 /*
976 * argv=command...
977 */
978 else if (strncasecmp("argv=", *argv, sizeof("argv=") - 1) == 0) {
979 *argv += sizeof("argv=") - 1; /* XXX clobbers argv */
980 attr->command = argv;
981 break;
982 }
983
984 /*
985 * Bad.
986 */
987 else
988 msg_fatal("unknown attribute name: %s", *argv);
989 }
990
991 /*
992 * Sanity checks. Verify that every member has an acceptable value.
993 */
994 if (user == 0)
995 msg_fatal("missing user= command-line attribute");
996 if (attr->command == 0)
997 msg_fatal("missing argv= command-line attribute");
998 if (attr->uid == 0)
999 msg_fatal("user= command-line attribute specifies root privileges");
1000 if (attr->uid == var_owner_uid)
1001 msg_fatal("user= command-line attribute specifies mail system owner %s",
1002 var_mail_owner);
1003 if (attr->gid == 0)
1004 msg_fatal("user= command-line attribute specifies privileged group id 0");
1005 if (attr->gid == var_owner_gid)
1006 msg_fatal("user= command-line attribute specifies mail system owner %s group id %ld",
1007 var_mail_owner, (long) attr->gid);
1008 if (attr->gid == var_sgid_gid)
1009 msg_fatal("user= command-line attribute specifies mail system %s group id %ld",
1010 var_sgid_group, (long) attr->gid);
1011
1012 /*
1013 * Give the poor tester a clue of what is going on.
1014 */
1015 if (msg_verbose)
1016 msg_info("%s: uid %ld, gid %ld, flags %d, size %ld",
1017 myname, (long) attr->uid, (long) attr->gid,
1018 attr->flags, (long) attr->size_limit);
1019}
1020
1021/* eval_command_status - do something with command completion status */
1022
1023static int eval_command_status(int command_status, char *service,
1024 DELIVER_REQUEST *request, PIPE_ATTR *attr,
1025 DSN_BUF *why)
1026{
1027 RECIPIENT *rcpt;
1028 int status;
1029 int result = 0;
1030 int n;
1031 char *saved_text;
1032
1033 /*
1034 * Depending on the result, bounce or defer the message, and mark the
1035 * recipient as done where appropriate.
1036 */
1037 switch (command_status) {
1038 case PIPE_STAT_OK:
1039 /* Save the command output before dsb_update() clobbers it. */
1040 vstring_truncate(why->reason, trimblanks(STR(why->reason),
1041 VSTRING_LEN(why->reason)) - STR(why->reason));
1042 if (VSTRING_LEN(why->reason) > 0) {
1043 VSTRING_TERMINATE(why->reason);
1044 saved_text =
1045 vstring_export(vstring_sprintf(
1046 vstring_alloc(VSTRING_LEN(why->reason)),
1047 " (%.100s)", STR(why->reason)));
1048 } else
1049 saved_text = mystrdup(""); /* uses shared R/O storage */
1050 dsb_update(why, "2.0.0", (attr->flags & PIPE_OPT_FINAL_DELIVERY) ?
1051 "delivered" : "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY,
1052 "delivered via %s service%s", service, saved_text);
1053 myfree(saved_text);
1054 (void) DSN_FROM_DSN_BUF(why);
1055 for (n = 0; n < request->rcpt_list.len; n++) {
1056 rcpt = request->rcpt_list.info + n;
1057 status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
1058 request->queue_id, &request->msg_stats, rcpt,
1059 service, &why->dsn);
1060 if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
1061 deliver_completed(request->fp, rcpt->offset);
1062 result |= status;
1063 }
1064 break;
1065 case PIPE_STAT_BOUNCE:
1066 case PIPE_STAT_DEFER:
1067 (void) DSN_FROM_DSN_BUF(why);
1068 for (n = 0; n < request->rcpt_list.len; n++) {
1069 rcpt = request->rcpt_list.info + n;
1070 /* XXX Maybe encapsulate this with ndr_append(). */
1071 status = (STR(why->status)[0] != '4' ?
1072 bounce_append : defer_append)
1073 (DEL_REQ_TRACE_FLAGS(request->flags),
1074 request->queue_id,
1075 &request->msg_stats, rcpt,
1076 service, &why->dsn);
1077 if (status == 0)
1078 deliver_completed(request->fp, rcpt->offset);
1079 result |= status;
1080 }
1081 break;
1082 case PIPE_STAT_CORRUPT:
1083 /* XXX DSN should we send something? */
1084 result |= DEL_STAT_DEFER;
1085 break;
1086 default:
1087 msg_panic("eval_command_status: bad status %d", command_status);
1088 /* NOTREACHED */
1089 }
1090
1091 return (result);
1092}
1093
1094/* deliver_message - deliver message with extreme prejudice */
1095
1096static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
1097{
1098 const char *myname = "deliver_message";
1099 static PIPE_PARAMS conf;
1100 static PIPE_ATTR attr;
1101 RECIPIENT_LIST *rcpt_list = &request->rcpt_list;
1102 DSN_BUF *why = dsb_create();
1103 VSTRING *buf;
1104 ARGV *expanded_argv = 0;
1105 int deliver_status;
1106 int command_status;
1107 ARGV *export_env;
1108 const char *sender;
1109
1110#define DELIVER_MSG_CLEANUP() { \
1111 dsb_free(why); \
1112 if (expanded_argv) argv_free(expanded_argv); \
1113 }
1114
1115 if (msg_verbose)
1116 msg_info("%s: from <%s>", myname, request->sender);
1117
1118 /*
1119 * Sanity checks. The get_service_params() and get_service_attr()
1120 * routines also do some sanity checks. Look up service attributes and
1121 * config information only once. This is safe since the information comes
1122 * from a trusted source, not from the delivery request.
1123 */
1124 if (request->nexthop[0] == 0)
1125 msg_fatal("empty nexthop hostname");
1126 if (rcpt_list->len <= 0)
1127 msg_fatal("recipient count: %d", rcpt_list->len);
1128 if (attr.command == 0) {
1129 get_service_params(&conf, service);
1130 get_service_attr(&attr, argv);
1131 }
1132
1133 /*
1134 * The D flag cannot be specified for multi-recipient deliveries.
1135 */
1136 if ((attr.flags & MAIL_COPY_DELIVERED) && (rcpt_list->len > 1)) {
1137 dsb_simple(why, "4.3.5", "mail system configuration error");
1138 deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
1139 request, &attr, why);
1140 msg_warn("pipe flag `D' requires %s_destination_recipient_limit = 1",
1141 service);
1142 DELIVER_MSG_CLEANUP();
1143 return (deliver_status);
1144 }
1145
1146 /*
1147 * The O flag cannot be specified for multi-recipient deliveries.
1148 */
1149 if ((attr.flags & MAIL_COPY_ORIG_RCPT) && (rcpt_list->len > 1)) {
1150 dsb_simple(why, "4.3.5", "mail system configuration error");
1151 deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
1152 request, &attr, why);
1153 msg_warn("pipe flag `O' requires %s_destination_recipient_limit = 1",
1154 service);
1155 DELIVER_MSG_CLEANUP();
1156 return (deliver_status);
1157 }
1158
1159 /*
1160 * Check that this agent accepts messages this large.
1161 */
1162 if (attr.size_limit != 0 && request->data_size > attr.size_limit) {
1163 if (msg_verbose)
1164 msg_info("%s: too big: size_limit = %ld, request->data_size = %ld",
1165 myname, (long) attr.size_limit, request->data_size);
1166 dsb_simple(why, "5.2.3", "message too large");
1167 deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
1168 request, &attr, why);
1169 DELIVER_MSG_CLEANUP();
1170 return (deliver_status);
1171 }
1172
1173 /*
1174 * Don't deliver a trace-only request.
1175 */
1176 if (DEL_REQ_TRACE_ONLY(request->flags)) {
1177 RECIPIENT *rcpt;
1178 int status;
1179 int n;
1180
1181 deliver_status = 0;
1182 dsb_simple(why, "2.0.0", "delivers to command: %s", attr.command[0]);
1183 (void) DSN_FROM_DSN_BUF(why);
1184 for (n = 0; n < request->rcpt_list.len; n++) {
1185 rcpt = request->rcpt_list.info + n;
1186 status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
1187 request->queue_id, &request->msg_stats,
1188 rcpt, service, &why->dsn);
1189 if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
1190 deliver_completed(request->fp, rcpt->offset);
1191 deliver_status |= status;
1192 }
1193 DELIVER_MSG_CLEANUP();
1194 return (deliver_status);
1195 }
1196
1197 /*
1198 * Report mail delivery loops. By definition, this requires
1199 * single-recipient delivery. Don't silently lose recipients.
1200 */
1201 if (attr.flags & MAIL_COPY_DELIVERED) {
1202 DELIVERED_HDR_INFO *info;
1203 RECIPIENT *rcpt;
1204 int loop_found;
1205
1206 if (request->rcpt_list.len > 1)
1207 msg_panic("%s: delivered-to enabled with multi-recipient request",
1208 myname);
1209 info = delivered_hdr_init(request->fp, request->data_offset,
1210 FOLD_ADDR_ALL);
1211 rcpt = request->rcpt_list.info;
1212 loop_found = delivered_hdr_find(info, rcpt->address);
1213 delivered_hdr_free(info);
1214 if (loop_found) {
1215 dsb_simple(why, "5.4.6", "mail forwarding loop for %s",
1216 rcpt->address);
1217 deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
1218 request, &attr, why);
1219 DELIVER_MSG_CLEANUP();
1220 return (deliver_status);
1221 }
1222 }
1223
1224 /*
1225 * Deliver. Set the nexthop and sender variables, and expand the command
1226 * argument vector. Recipients will be expanded on the fly. XXX Rewrite
1227 * envelope and header addresses according to transport-specific
1228 * rewriting rules.
1229 */
1230 if (vstream_fseek(request->fp, request->data_offset, SEEK_SET) < 0)
1231 msg_fatal("seek queue file %s: %m", VSTREAM_PATH(request->fp));
1232
1233 /*
1234 * A non-empty null sender replacement is subject to the 'q' flag.
1235 */
1236 buf = vstring_alloc(10);
1237 sender = *request->sender ? request->sender : STR(attr.null_sender);
1238 if (*sender && (attr.flags & PIPE_OPT_QUOTE_LOCAL)) {
1239 quote_822_local(buf, sender);
1240 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, STR(buf));
1241 } else
1242 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, sender);
1243 if (attr.flags & PIPE_OPT_FOLD_HOST) {
1244 casefold(buf, request->nexthop);
1245 dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, STR(buf));
1246 } else
1247 dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop);
1248 vstring_sprintf(buf, "%ld", (long) request->data_size);
1249 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SIZE, STR(buf));
1250 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_ADDR,
1251 request->client_addr);
1252 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_HELO,
1253 request->client_helo);
1254 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_NAME,
1255 request->client_name);
1256 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PORT,
1257 request->client_port);
1258 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PROTO,
1259 request->client_proto);
1260 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_METHOD,
1261 request->sasl_method);
1262 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_USERNAME,
1263 request->sasl_username);
1264 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_SENDER,
1265 request->sasl_sender);
1266 dict_update(PIPE_DICT_TABLE, PIPE_DICT_QUEUE_ID,
1267 request->queue_id);
1268 vstring_free(buf);
1269
1270 if ((expanded_argv = expand_argv(service, attr.command,
1271 rcpt_list, attr.flags)) == 0) {
1272 dsb_simple(why, "4.3.5", "mail system configuration error");
1273 deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
1274 request, &attr, why);
1275 DELIVER_MSG_CLEANUP();
1276 return (deliver_status);
1277 }
1278 export_env = mail_parm_split(VAR_EXPORT_ENVIRON, var_export_environ);
1279
1280 command_status = pipe_command(request->fp, why,
1281 CA_PIPE_CMD_UID(attr.uid),
1282 CA_PIPE_CMD_GID(attr.gid),
1283 CA_PIPE_CMD_SENDER(sender),
1284 CA_PIPE_CMD_COPY_FLAGS(attr.flags),
1285 CA_PIPE_CMD_ARGV(expanded_argv->argv),
1286 CA_PIPE_CMD_TIME_LIMIT(conf.time_limit),
1287 CA_PIPE_CMD_EOL(STR(attr.eol)),
1288 CA_PIPE_CMD_EXPORT(export_env->argv),
1289 CA_PIPE_CMD_CWD(attr.exec_dir),
1290 CA_PIPE_CMD_CHROOT(attr.chroot_dir),
1291 CA_PIPE_CMD_ORIG_RCPT(rcpt_list->info[0].orig_addr),
1292 CA_PIPE_CMD_DELIVERED(rcpt_list->info[0].address),
1293 CA_PIPE_CMD_END);
1294 argv_free(export_env);
1295
1296 deliver_status = eval_command_status(command_status, service, request,
1297 &attr, why);
1298
1299 /*
1300 * Clean up.
1301 */
1302 DELIVER_MSG_CLEANUP();
1303
1304 return (deliver_status);
1305}
1306
1307/* pipe_service - perform service for client */
1308
1309static void pipe_service(VSTREAM *client_stream, char *service, char **argv)
1310{
1311 DELIVER_REQUEST *request;
1312 int status;
1313
1314 /*
1315 * This routine runs whenever a client connects to the UNIX-domain socket
1316 * dedicated to delivery via external command. What we see below is a
1317 * little protocol to (1) tell the queue manager that we are ready, (2)
1318 * read a request from the queue manager, and (3) report the completion
1319 * status of that request. All connection-management stuff is handled by
1320 * the common code in single_server.c.
1321 */
1322 if ((request = deliver_request_read(client_stream)) != 0) {
1323 status = deliver_message(request, service, argv);
1324 deliver_request_done(client_stream, request, status);
1325 }
1326}
1327
1328/* pre_accept - see if tables have changed */
1329
1330static void pre_accept(char *unused_name, char **unused_argv)
1331{
1332 const char *table;
1333
1334 if ((table = dict_changed_name()) != 0) {
1335 msg_info("table %s has changed -- restarting", table);
1336 exit(0);
1337 }
1338}
1339
1340/* drop_privileges - drop privileges most of the time */
1341
1342static void drop_privileges(char *unused_name, char **unused_argv)
1343{
1344 set_eugid(var_owner_uid, var_owner_gid);
1345}
1346
1347/* pre_init - initialize */
1348
1349static void pre_init(char *unused_name, char **unused_argv)
1350{
1351 flush_init();
1352}
1353
1354MAIL_VERSION_STAMP_DECLARE;
1355
1356/* main - pass control to the single-threaded skeleton */
1357
1358int main(int argc, char **argv)
1359{
1360 static const CONFIG_TIME_TABLE time_table[] = {
1361 VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0,
1362 0,
1363 };
1364 static const CONFIG_STR_TABLE str_table[] = {
1365 VAR_PIPE_DSN_FILTER, DEF_PIPE_DSN_FILTER, &var_pipe_dsn_filter, 0, 0,
1366 0,
1367 };
1368
1369 /*
1370 * Fingerprint executables and core dumps.
1371 */
1372 MAIL_VERSION_STAMP_ALLOCATE;
1373
1374 single_server_main(argc, argv, pipe_service,
1375 CA_MAIL_SERVER_TIME_TABLE(time_table),
1376 CA_MAIL_SERVER_STR_TABLE(str_table),
1377 CA_MAIL_SERVER_PRE_INIT(pre_init),
1378 CA_MAIL_SERVER_POST_INIT(drop_privileges),
1379 CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
1380 CA_MAIL_SERVER_PRIVILEGED,
1381 CA_MAIL_SERVER_BOUNCE_INIT(VAR_PIPE_DSN_FILTER,
1382 &var_pipe_dsn_filter),
1383 0);
1384}
1385